package com.okilo.online.app.request

import okhttp3.Call
import okhttp3.Callback
import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit

/**
 * Okhttp 请求工具封装
 */
class OkHttpUtil private constructor() {
    private val okHttpClient: OkHttpClient

    init {
        val builder = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
        okHttpClient = builder.build()
    }

    companion object {
        @Volatile
        private var instance: OkHttpUtil? = null

        fun getInstance(): OkHttpUtil =
            instance ?: synchronized(this) {
                instance ?: OkHttpUtil().also { instance = it }
            }
    }

    /**
     * GET 请求
     * @param url 请求地址
     * @param params 请求参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    fun get(url: String, params: Map<String, String>? = null, headers: Map<String, String>? = null, callback: HttpCallback) {
        val requestBuilder = Request.Builder()

        // 添加请求头
        headers?.forEach { (key, value) ->
            requestBuilder.addHeader(key, value)
        }

        // 构建带参数的URL
        val finalUrl = buildUrlWithParams(url, params)
        requestBuilder.url(finalUrl).get()

        val request = requestBuilder.build()
        executeRequest(request, callback)
    }

    /**
     * POST 表单请求
     * @param url 请求地址
     * @param params 表单参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    fun postForm(url: String, params: Map<String, String>? = null, headers: Map<String, String>? = null, callback: HttpCallback) {
        val formBuilder = FormBody.Builder()
        params?.forEach { (key, value) ->
            formBuilder.add(key, value)
        }

        val formBody = formBuilder.build()
        post(url, formBody, headers, callback)
    }

    /**
     * POST JSON 请求
     * @param url 请求地址
     * @param json JSON字符串
     * @param headers 请求头
     * @param callback 回调接口
     */
    fun postJson(url: String, json: String, headers: Map<String, String>? = null, callback: HttpCallback) {
        val mediaType = "application/json; charset=utf-8".toMediaType()
        val requestBody = json.toRequestBody(mediaType)
        post(url, requestBody, headers, callback)
    }

    /**
     * 文件上传
     * @param url 请求地址
     * @param fileParamName 文件参数名
     * @param filePath 文件路径
     * @param params 其他参数
     * @param headers 请求头
     * @param callback 回调接口
     */
    fun uploadFile(url: String, fileParamName: String, filePath: String, params: Map<String, String>? = null, headers: Map<String, String>? = null, callback: HttpCallback) {
        val file = File(filePath)
        if (!file.exists()) {
            callback.onFailure(IOException("File not exists"))
            return
        }

        val requestBodyBuilder = MultipartBody.Builder()
            .setType(MultipartBody.FORM)

        // 添加文件
        val fileBody = file.asRequestBody("application/octet-stream".toMediaType())
        requestBodyBuilder.addFormDataPart(fileParamName, file.name, fileBody)

        // 添加其他参数
        params?.forEach { (key, value) ->
            requestBodyBuilder.addFormDataPart(key, value)
        }

        val requestBody = requestBodyBuilder.build()
        post(url, requestBody, headers, callback)
    }

    /**
     * 通用 POST 请求
     */
    private fun post(url: String, requestBody: RequestBody, headers: Map<String, String>?, callback: HttpCallback) {
        val requestBuilder = Request.Builder()
            .url(url)
            .post(requestBody)

        headers?.forEach { (key, value) ->
            requestBuilder.addHeader(key, value)
        }

        val request = requestBuilder.build()
        executeRequest(request, callback)
    }

    /**
     * 执行请求
     */
    private fun executeRequest(request: Request, callback: HttpCallback) {
        okHttpClient.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback.onFailure(e)
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    val body = response.body
                    callback.onSuccess(body.string())
                } else {
                    callback.onFailure(IOException("Unexpected code ${response.code}"))
                }
            }
        })
    }

    /**
     * 构建带参数的URL
     */
    private fun buildUrlWithParams(url: String, params: Map<String, String>?): String {
        if (params.isNullOrEmpty()) {
            return url
        }

        val urlBuilder = url.toHttpUrlOrNull()?.newBuilder() ?: return url
        params.forEach { (key, value) ->
            urlBuilder.addQueryParameter(key, value)
        }
        return urlBuilder.build().toString()
    }

    /**
     * 请求回调接口
     */
    interface HttpCallback {
        fun onSuccess(response: String)
        fun onFailure(e: IOException)
    }
}